/**
 * Licensed under the MIT License
 *
 * Copyright (c) 2010 Alexandre Croiseaux
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */
package marcel.display.gui.components {
	
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import marcel.display.View;
	import swc.form.SliderAsset;
	

	/**
	* Dispatched when the value has changed
	* @eventType flash.events.Event.CHANGE
	*/
	[Event(name = "change", type = "flash.events.Event")]

	/**
	 * A Slider component class.
	 * The graphics are editable inside the form.fla file
	 * @author Alexandre Croiseaux
	 * @author Benoit Saint-Maxent
	 */
	public class Slider extends View
	{
		//--------------------------------------------------------------------------
		//
		//  Private vars
		//
		//--------------------------------------------------------------------------
		private var _gfx:SliderAsset;
		private var _mcBg : MovieClip;
		private var _mcCursor : MovieClip;
		private var _mcOver : MovieClip;
		private var _mcTimeline : MovieClip;
		private var _oExtremeValues : Point;
		private var _oExtremePos : Point;
		private var _nValue : Number;
		private var _nMinWidthBg : Number = 0;
		private var _nMinWidthOver : Number = 0;
		private var _nMinWidthTimeline : Number = 0;

		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------
		/**
		 * Constructs a new Slider instance
		 * @param	minValue	the value when the slider is ont the top left
		 * @param	maxValue	the value when the slider is ont the top right
		 */
		public function Slider(minValue:Number, maxValue:Number)
		{
			_oExtremeValues = new Point(minValue, maxValue);
			
			_gfx = new SliderAsset();
			addChild(_gfx);
			_mcBg = _gfx.mcBg;
			_mcTimeline = _gfx.mcTimeline;
			_mcOver = _gfx.mcOver;
			_mcCursor = _gfx.mcCursor;
			
			if(_mcBg.scale9Grid is Rectangle)
						_nMinWidthBg = _mcBg.scale9Grid.x + (_mcBg.width - _mcBg.scale9Grid.x - _mcBg.scale9Grid.width);
			if(_mcOver is MovieClip && _mcOver.scale9Grid is Rectangle)
						_nMinWidthOver = _mcOver.scale9Grid.x + (_mcOver.width - _mcOver.scale9Grid.x - _mcOver.scale9Grid.width);
			if(_mcTimeline is MovieClip && _mcTimeline.scale9Grid is Rectangle)
						_nMinWidthTimeline = _mcTimeline.scale9Grid.x + (_mcTimeline.width - _mcTimeline.scale9Grid.x - _mcTimeline.scale9Grid.width);
			
			setWidth(_mcBg.width);
			setValue(_oExtremeValues.x);
			
			_initInteractivity();
		}
		
		
		//--------------------------------------------------------------------------
		//
		//  Public methods
		//
		//--------------------------------------------------------------------------
		/**
		 * Sets the min and max values
		 * @param	minValue	the value when the slider is ont the top left
		 * @param	maxValue	the value when the slider is ont the top right
		 */
		public function setExtremeValues(minValue:Number, maxValue:Number) : void {
			_oExtremeValues = new Point(minValue, maxValue);
			if(!isNaN(_nValue)) setValue(_nValue);
		}

		/**
		 * updates the width of the slider
		 * @param	nWidth	the width in pixels
		 */
		public function setWidth(nWidth : Number) : void {
			_mcBg.width = Math.max(nWidth, _nMinWidthBg);
			if(_mcOver is MovieClip) _mcOver.width = Math.max(nWidth, _nMinWidthOver);
			_oExtremePos = new Point(0, _mcBg.width - _mcCursor.width);
			if(!isNaN(_nValue)) setValue(_nValue);
		}
		
		/**
		 * Sets the current value of the slider, and refreshes the view
		 * @param	oValue	the value between min &amp; max values
		 */
		public function setValue(oValue:Number) : void {
			var nValue : Number = Number(oValue);
			nValue = Math.max(_oExtremeValues.x, nValue);
			nValue = Math.min(_oExtremeValues.y, nValue);
			
			_nValue = nValue;
			refreshView();
			
			dispatchEvent(new Event(Event.CHANGE));
		}
		
		/**
		 * Returns the value of the slider
		 * @return	A number between min &amp; max
		 */
		public function getValue():Number {
			return _nValue;
		}
		
		/**
		 * Releases the current scroller by removing all the listeners
		 */
		public function release() : void {
			removeEventListener(MouseEvent.MOUSE_DOWN, _onPressView);
			stage.removeEventListener(MouseEvent.MOUSE_UP, _onReleaseView);
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, _onMouseMove);
		}
		//--------------------------------------------------------------------------
		//
		//  Private methods
		//
		//--------------------------------------------------------------------------
		/**
		 * @private
		 */
		protected function refreshView() : void {
			var nPerc : Number = (_nValue - _oExtremeValues.x) / (_oExtremeValues.y - _oExtremeValues.x);
			var nX : Number = _oExtremePos.y * nPerc;
			_mcCursor.x = nX;
			if(_mcTimeline is MovieClip) _mcTimeline.width = Math.max(nX, _nMinWidthTimeline);
		}

		private function _initInteractivity() : void {
			mouseChildren = false;
			buttonMode = true;
			tabEnabled = false;
			addEventListener(MouseEvent.MOUSE_DOWN, _onPressView);
		}
		
		private function _onPressView(event : MouseEvent) : void {
			_onMouseMove();
			stage.addEventListener(MouseEvent.MOUSE_MOVE, _onMouseMove);
			stage.addEventListener(MouseEvent.MOUSE_UP, _onReleaseView);
		}

		private function _onReleaseView(event : MouseEvent) : void {
			stage.removeEventListener(MouseEvent.MOUSE_UP, _onReleaseView);
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, _onMouseMove);
		}
		
		private function _onMouseMove(event : MouseEvent = null) : void {
			var nX : Number = mouseX;
			nX = Math.max(0, nX);
			nX = Math.min(_mcBg.width, nX);
			var nPerc : Number = nX / _mcBg.width;
			var nValue : Number = ((_oExtremeValues.y - _oExtremeValues.x) * nPerc) + _oExtremeValues.x;
			setValue(nValue);
		}
	}
}
